home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 October / CHIP Turkiye Ekim 2000.iso / prog / naps / 04 / setup.exe / Gnucleus / MainFrm.cpp < prev    next >
C/C++ Source or Header  |  2000-07-15  |  24KB  |  907 lines

  1. /********************************************************************************
  2.  
  3.     Gnucleus - A node application for the Gnutella network
  4.     Copyright (C) 2000 John Marshall
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     For support, questions, comments, etc...
  20.     E-Mail: 
  21.         swabby@c0re.net
  22.     
  23.     Address:
  24.         21 Cadogan Way
  25.         Nashua, NH, USA 03062
  26.  
  27. ********************************************************************************/
  28.  
  29. // MainFrm.cpp : implementation of the CMainFrame class
  30. //
  31.  
  32. #include "stdafx.h"
  33. #include "Gnucleus.h"
  34. #include "GnucleusDoc.h"
  35.  
  36. #include "ViewConnect.h"
  37. #include "MainFrm.h"
  38.  
  39. #include "GnuHash.h"
  40. #include "GnuControl.h"
  41.  
  42. #define    WM_ICON_NOTIFY            WM_USER+10
  43.  
  44. #ifdef _DEBUG
  45. #define new DEBUG_NEW
  46. #undef THIS_FILE
  47. static char THIS_FILE[] = __FILE__;
  48. #endif
  49.  
  50. /////////////////////////////////////////////////////////////////////////////
  51. // CMainFrame
  52.  
  53. IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
  54.  
  55. BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
  56.     //{{AFX_MSG_MAP(CMainFrame)
  57.     ON_WM_CREATE()
  58.     ON_WM_TIMER()
  59.     ON_COMMAND(ID_OPEN, OnOpenFromTray)
  60.     ON_WM_SHOWWINDOW()
  61.     ON_WM_NCACTIVATE()
  62.     ON_WM_NCLBUTTONUP()
  63.     ON_WM_NCLBUTTONDOWN()
  64.     ON_WM_NCMOUSEMOVE()
  65.     ON_WM_NCPAINT()
  66.     ON_MESSAGE(WM_ICON_NOTIFY, OnTrayNotification)
  67.     ON_WM_PAINT()
  68.     //}}AFX_MSG_MAP
  69. END_MESSAGE_MAP()
  70.  
  71. static UINT indicators[] =
  72. {
  73.     ID_SEPARATOR,     // status line indicator
  74.     ID_INDICATOR_RECV,
  75.     ID_INDICATOR_SEND
  76. };
  77.  
  78. /////////////////////////////////////////////////////////////////////////////
  79. // CMainFrame construction/destruction
  80.  
  81. CMainFrame::CMainFrame()
  82. {
  83.     Doc = (CGnucleusDoc *) ((CGnucleusApp *) AfxGetApp())->MasterDoc;
  84.    m_bUseTrayIcon = TRUE;
  85.     Strike = 0;
  86.    InitializeTrayIcon();
  87. }
  88.  
  89. CMainFrame::~CMainFrame()
  90. {
  91.     RemoveIcon();
  92.     m_wndTrayIcon.DestroyWindow();
  93. }
  94.  
  95. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
  96. {
  97.     if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
  98.         return -1;
  99.     
  100.     if (!m_wndToolBar.CreateEx(this) ||
  101.         !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
  102.     {
  103.         TRACE0("Failed to create toolbar\n");
  104.         return -1;      // fail to create
  105.     }
  106.     if (!m_wndDlgBar.Create(this, IDR_MAINFRAME, 
  107.         CBRS_ALIGN_TOP, AFX_IDW_DIALOGBAR))
  108.     {
  109.         TRACE0("Failed to create dialogbar\n");
  110.         return -1;        // fail to create
  111.     }
  112.     else
  113.     {
  114.         CComboBox* cbptr = ((CComboBox *) m_wndDlgBar.GetDlgItem(IDC_COMBO_SPEED));
  115.  
  116.         cbptr->InsertString(0, "T3 (or Greater)");
  117.         cbptr->InsertString(0, "T1");
  118.         cbptr->InsertString(0, "DSL");
  119.         cbptr->InsertString(0, "Cable");
  120.         cbptr->InsertString(0, "ISDN-128K");
  121.         cbptr->InsertString(0, "ISDN-56K");
  122.         cbptr->InsertString(0, "56K Modem");
  123.         cbptr->InsertString(0, "33.6 Modem");
  124.         cbptr->InsertString(0, "28.8 Modem");
  125.         cbptr->InsertString(0, "14.4 Modem");
  126.         cbptr->InsertString(0, "");
  127.     }
  128.  
  129.     if (!m_wndReBar.Create(this) ||
  130.         !m_wndReBar.AddBar(&m_wndToolBar) ||
  131.         !m_wndReBar.AddBar(&m_wndDlgBar))
  132.     {
  133.         TRACE0("Failed to create rebar\n");
  134.         return -1;      // fail to create
  135.     }
  136.  
  137.     if (!m_wndStatusBar.Create(this) ||
  138.         !m_wndStatusBar.SetIndicators(indicators,
  139.           sizeof(indicators)/sizeof(UINT)))
  140.     {
  141.         TRACE0("Failed to create status bar\n");
  142.         return -1;      // fail to create
  143.     }
  144.     else
  145.     {
  146.         m_wndStatusBar.SetPaneInfo(1, ID_INDICATOR_RECV, SBPS_NORMAL, 140);
  147.         m_wndStatusBar.SetPaneInfo(2, ID_INDICATOR_SEND, SBPS_NORMAL, 125);
  148.     }
  149.  
  150.     if (!CreateTrayIcon(this, WM_ICON_NOTIFY, _T("Gnucleus"), AfxGetApp()->LoadIcon(IDR_MAINFRAME),
  151.                             IDR_TRAY))
  152.     {
  153.         TRACE0("Failed to create system tray icon.\n");
  154.         return -1;      // fail to create
  155.     }
  156.     else
  157.     {
  158.         HideIcon();
  159.       if (m_bOwnerCreated) 
  160.       {
  161.          ShowTaskBarButton(TRUE);
  162.       }
  163.     }
  164.  
  165.    // TODO: Remove this if you don't want tool tips
  166.     m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
  167.         CBRS_TOOLTIPS | CBRS_FLYBY);
  168.  
  169.     UpdateTimer = SetTimer(1, 1000, 0);    
  170.  
  171.     return 0;
  172. }
  173.  
  174. void CMainFrame::InitializeTrayIcon()
  175. {
  176.     memset(&m_tnd, 0, sizeof(m_tnd));
  177.     m_bEnabled   = FALSE;
  178.     m_bHidden    = FALSE;
  179.     m_hSavedIcon = NULL;
  180.     m_DefaultMenuItemID = 0;
  181.     m_DefaultMenuItemByPos = TRUE;
  182. }
  183.  
  184. BOOL CMainFrame::CreateTrayIcon(CWnd* pParent, UINT uCallbackMessage, LPCTSTR szToolTip, 
  185.                          HICON icon, UINT uID)
  186. {
  187.     // this is only for Windows 95 (or higher)
  188.     VERIFY(m_bEnabled = ( GetVersion() & 0xff ) >= 4);
  189.     if (!m_bEnabled) return FALSE;
  190.  
  191.     // Make sure Notification window is valid (not needed - CJM)
  192.     // VERIFY(m_bEnabled = (pParent && ::IsWindow(pParent->GetSafeHwnd())));
  193.     // if (!m_bEnabled) return FALSE;
  194.     
  195.     // Make sure we avoid conflict with other messages
  196.     ASSERT(uCallbackMessage >= WM_USER);
  197.  
  198.     // Tray only supports tooltip text up to 64 characters
  199.     ASSERT(_tcslen(szToolTip) <= 64);
  200.  
  201.     // Create an invisible window
  202.     m_wndTrayIcon.CreateEx(0, AfxRegisterWndClass(0), _T(""), WS_POPUP, 0,0,10,10, NULL, 0);
  203.  
  204.     // load up the NOTIFYICONDATA structure
  205.     m_tnd.cbSize = sizeof(NOTIFYICONDATA);
  206.     m_tnd.hWnd   = pParent->GetSafeHwnd()? pParent->GetSafeHwnd() : m_wndTrayIcon.GetSafeHwnd();
  207.     m_tnd.uID    = uID;
  208.     m_tnd.hIcon  = icon;
  209.     m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  210.     m_tnd.uCallbackMessage = uCallbackMessage;
  211.     _tcscpy(m_tnd.szTip, szToolTip);
  212.  
  213.     // Set the tray icon
  214.     VERIFY(m_bEnabled = Shell_NotifyIcon(NIM_ADD, &m_tnd));
  215.     return m_bEnabled;
  216. }
  217.  
  218. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
  219.    if (!CMDIFrameWnd::PreCreateWindow(cs)) return FALSE; 
  220.    if (!m_bOwnerCreated) // "dialog-is-created" flag 
  221.    { 
  222.      // m_MainFrameOwner - CDialog object mapped to the resource dialog template 
  223.      m_bOwnerCreated = m_MainFrameOwner.Create(IDD_OWNERFRAME); 
  224.      if (m_bOwnerCreated) m_MainFrameOwner.ShowWindow(SW_HIDE); 
  225.    }; 
  226.  
  227.    // set the dialog as a parent of CMainFrame window 
  228.    if (m_bOwnerCreated) 
  229.    {
  230.       cs.hwndParent = m_MainFrameOwner.GetSafeHwnd(); 
  231.    }
  232.  
  233.    return TRUE; 
  234.  
  235. BOOL CMainFrame::ShowTaskBarButton(BOOL bVisible) 
  236.     if (!m_bOwnerCreated) return FALSE; 
  237.  
  238. //    ShowWindow(SW_HIDE);    // seems to cause various problems,
  239.                             // ranging from flashing windows to the title bar disappearing
  240.  
  241.     if (bVisible) 
  242.         ModifyStyleEx(0, WS_EX_APPWINDOW); 
  243.     else 
  244.         ModifyStyleEx(WS_EX_APPWINDOW, 0);
  245.  
  246. //    ShowWindow(SW_SHOW);
  247.  
  248.     return TRUE; 
  249. /////////////////////////////////////////////////////////////////////////////
  250. // CMainFrame diagnostics
  251.  
  252. #ifdef _DEBUG
  253. void CMainFrame::AssertValid() const
  254. {
  255.     CMDIFrameWnd::AssertValid();
  256. }
  257.  
  258. void CMainFrame::Dump(CDumpContext& dc) const
  259. {
  260.     CMDIFrameWnd::Dump(dc);
  261. }
  262.  
  263. #endif //_DEBUG
  264.  
  265. /////////////////////////////////////////////////////////////////////////////
  266. // CMainFrame message handlers
  267.  
  268. CDialogBar* CMainFrame::GetDialogBar()
  269. {
  270.     return &m_wndDlgBar;
  271. }
  272.  
  273. void CMainFrame::OnTimer(UINT nIDEvent) 
  274. {    
  275.  
  276.     if(nIDEvent == UpdateTimer)
  277.     {
  278.         int  decimal, sign;
  279.         float BytesIn = (float) Doc->GnuComm->BytesIn,
  280.               BytesOut = (float) Doc->GnuComm->BytesOut,
  281.               ByteLimit = (float) Doc->m_LimitTotal,
  282.               Kilo = 1024;
  283.  
  284.         // call thread flow control OnTimer only once a second
  285.         Doc->GnuComm->OnTimer();
  286.  
  287.         
  288.         // Reset
  289.         Doc->GnuComm->BytesIn  = 0;
  290.         Doc->GnuComm->BytesOut = 0;
  291.  
  292.         // The the estimated speed for gnucleus
  293.         Doc->m_EstSpeed = GetEstSpeed(BytesIn * 8 / 1024);
  294.  
  295.         // Receive status bar update
  296.         float Old_RecvSpeed = atof(m_wndStatusBar.GetPaneText(1));
  297. //        CString Speed = _fcvt( ((BytesIn / Kilo) + Old_RecvSpeed) / 2, 2, &decimal, &sign );
  298.         CString Speed = _fcvt( Doc->GnuComm->m_dwBytesPerSecIn / Kilo, 2, &decimal, &sign );
  299.         Speed.Insert(decimal, ".");
  300.  
  301.         CString Title = "Receive rate:   ";
  302.         Title += Speed;
  303.         Title += " KB/s";
  304.         m_wndStatusBar.SetPaneText(1, Title);
  305.  
  306.         // Send status bar update
  307.         float Old_SendSpeed = atof(m_wndStatusBar.GetPaneText(2));
  308. //        Speed = _fcvt( ((BytesOut / Kilo) + Old_SendSpeed) / 2, 2, &decimal, &sign );
  309.         Speed = _fcvt( Doc->GnuComm->m_dwBytesPerSecOut / Kilo, 2, &decimal, &sign );
  310.         Speed.Insert(decimal, ".");
  311.  
  312.         Title = "Send rate:   ";
  313.         Title += Speed;
  314.         Title += " KB/s";
  315.         m_wndStatusBar.SetPaneText(2, Title);
  316.  
  317. /*
  318.         // Drop if limit hit
  319.         float AverageSpeed = (((BytesOut + BytesIn) / Kilo) + (Old_RecvSpeed + Old_SendSpeed)) / 2;
  320.  
  321.         if(ByteLimit != 0)
  322.             if(ByteLimit < AverageSpeed)
  323.                 if(AverageSpeed - ByteLimit > 1)
  324.                     Strike++;
  325.                 else
  326.                     Strike = 0;
  327. */
  328.  
  329.         // If limit is hit 3 times in a row, drop the connection
  330.         if(Strike > 10)
  331.         {    
  332.             Strike = 0;
  333.  
  334.             Doc->m_ConnectNum--;
  335.  
  336.             if( Doc->m_ConnectNum == 0)
  337.                 AfxMessageBox("Not enough bandwidth to support Gnucleus.");
  338.  
  339.             ((CViewConnect * ) ((CGnucleusApp *) AfxGetApp())->ConnectFrame->GetActiveView())->RemoveFirstNode();
  340.         }
  341.     }
  342.  
  343.     CMDIFrameWnd::OnTimer(nIDEvent);
  344. }
  345.  
  346. DWORD CMainFrame::GetEstSpeed(DWORD CurrentSpeed)
  347. {
  348.     if(CurrentSpeed <= Doc->m_EstSpeed)
  349.         return Doc->m_EstSpeed;
  350.     else
  351.     {
  352.         if(CurrentSpeed > 45000)
  353.             return 45000;
  354.         if(CurrentSpeed > 1500)
  355.             return 1500;
  356.         if(CurrentSpeed > 768)
  357.             return 768;
  358.         if(CurrentSpeed > 384)
  359.             return 384;
  360.         if(CurrentSpeed > 128)
  361.             return 128;
  362.         if(CurrentSpeed > 56)
  363.             return 56;
  364.         if(CurrentSpeed > 53)
  365.             return 53;
  366.         if(CurrentSpeed > 29)
  367.             return 29;
  368.         if(CurrentSpeed > 14)
  369.             return 14;
  370.     }
  371.     
  372.     return 0;
  373. }
  374.  
  375. BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) 
  376. {
  377.     // Entering return in they keyword box submits a search
  378.     if(wParam == 1 && lParam == 0)
  379.     {
  380.         ((CGnucleusApp *) AfxGetApp())->OnButtonSearch();
  381.     }
  382.     
  383.     return CMDIFrameWnd::OnCommand(wParam, lParam);
  384. }
  385.  
  386. void CMainFrame::OnOpenFromTray() 
  387. {
  388.     this->ShowWindow(SW_RESTORE);
  389.    HideIcon();
  390.    ShowTaskBarButton(TRUE);
  391. }
  392.  
  393. void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
  394. {
  395.     CMDIFrameWnd::OnShowWindow(bShow, nStatus);
  396.     
  397.     // I don't know what the following code needs to be here for,
  398.     // but it makes a massive headache on Win 9x (stack overflow).
  399. /*    
  400.     if (bShow)
  401.     {
  402.         HideIcon();
  403.         ShowTaskBarButton(TRUE);
  404.     }
  405. */
  406. }
  407.  
  408. /////////////////////////////////////////////////////////////////////////////
  409. // Tray Icon manipulation
  410.  
  411. void CMainFrame::MoveToRight()
  412. {
  413.     HideIcon();
  414.     ShowIcon();
  415. }
  416.  
  417. void CMainFrame::RemoveIcon()
  418. {
  419.     if (!m_bEnabled) return;
  420.  
  421.     m_tnd.uFlags = 0;
  422.     Shell_NotifyIcon(NIM_DELETE, &m_tnd);
  423.     m_bEnabled = FALSE;
  424. }
  425.  
  426. void CMainFrame::HideIcon()
  427. {
  428.     if (m_bEnabled && !m_bHidden) {
  429.         m_tnd.uFlags = NIF_ICON;
  430.         Shell_NotifyIcon (NIM_DELETE, &m_tnd);
  431.         m_bHidden = TRUE;
  432.     }
  433. }
  434.  
  435. void CMainFrame::ShowIcon()
  436. {
  437.     if (m_bEnabled && m_bHidden) {
  438.         m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  439.         Shell_NotifyIcon(NIM_ADD, &m_tnd);
  440.         m_bHidden = FALSE;
  441.     }
  442. }
  443.  
  444. BOOL CMainFrame::SetIcon(HICON hIcon)
  445. {
  446.     if (!m_bEnabled) return FALSE;
  447.  
  448.     m_tnd.uFlags = NIF_ICON;
  449.     m_tnd.hIcon = hIcon;
  450.  
  451.     return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  452. }
  453.  
  454. BOOL CMainFrame::SetIcon(LPCTSTR lpszIconName)
  455. {
  456.     HICON hIcon = AfxGetApp()->LoadIcon(lpszIconName);
  457.  
  458.     return SetIcon(hIcon);
  459. }
  460.  
  461. BOOL CMainFrame::SetIcon(UINT nIDResource)
  462. {
  463.     HICON hIcon = AfxGetApp()->LoadIcon(nIDResource);
  464.  
  465.     return SetIcon(hIcon);
  466. }
  467.  
  468. BOOL CMainFrame::SetStandardIcon(LPCTSTR lpIconName)
  469. {
  470.     HICON hIcon = LoadIcon(NULL, lpIconName);
  471.  
  472.     return SetIcon(hIcon);
  473. }
  474.  
  475. BOOL CMainFrame::SetStandardIcon(UINT nIDResource)
  476. {
  477.     HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(nIDResource));
  478.  
  479.     return SetIcon(hIcon);
  480. }
  481.  
  482. HICON CMainFrame::GetIcon() const
  483. {
  484.     return (m_bEnabled)? m_tnd.hIcon : NULL;
  485. }
  486.  
  487. /////////////////////////////////////////////////////////////////////////////
  488. // Tray Icon tooltip text manipulation
  489.  
  490. BOOL CMainFrame::SetTooltipText(LPCTSTR pszTip)
  491. {
  492.     if (!m_bEnabled) return FALSE;
  493.  
  494.     m_tnd.uFlags = NIF_TIP;
  495.     _tcscpy(m_tnd.szTip, pszTip);
  496.  
  497.     return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  498. }
  499.  
  500. BOOL CMainFrame::SetTooltipText(UINT nID)
  501. {
  502.     CString strText;
  503.     VERIFY(strText.LoadString(nID));
  504.  
  505.     return SetTooltipText(strText);
  506. }
  507.  
  508. CString CMainFrame::GetTooltipText() const
  509. {
  510.     CString strText;
  511.     if (m_bEnabled)
  512.         strText = m_tnd.szTip;
  513.  
  514.     return strText;
  515. }
  516.  
  517. /////////////////////////////////////////////////////////////////////////////
  518. // Tray Icon notification window stuff
  519.  
  520. BOOL CMainFrame::SetNotificationWnd(CWnd* pWnd)
  521. {
  522.     if (!m_bEnabled) return FALSE;
  523.  
  524.     // Make sure Notification window is valid
  525.     ASSERT(pWnd && ::IsWindow(pWnd->GetSafeHwnd()));
  526.  
  527.     m_tnd.hWnd = pWnd->GetSafeHwnd();
  528.     m_tnd.uFlags = 0;
  529.  
  530.     return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  531. }
  532.  
  533. CWnd* CMainFrame::GetNotificationWnd() const
  534. {
  535.     return CWnd::FromHandle(m_tnd.hWnd);
  536. }
  537.  
  538. /////////////////////////////////////////////////////////////////////////////
  539. // Tray Icon menu manipulation
  540.  
  541. BOOL CMainFrame::SetMenuDefaultItem(UINT uItem, BOOL bByPos)
  542. {
  543.     if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos == bByPos)) 
  544.         return TRUE;
  545.  
  546.     m_DefaultMenuItemID = uItem;
  547.     m_DefaultMenuItemByPos = bByPos;   
  548.  
  549.     CMenu menu, *pSubMenu;
  550.  
  551.     if (!menu.LoadMenu(m_tnd.uID)) return FALSE;
  552.     if (!(pSubMenu = menu.GetSubMenu(0))) return FALSE;
  553.  
  554.     ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos);
  555.  
  556.     return TRUE;
  557. }
  558.  
  559. void CMainFrame::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos)
  560. {
  561.     uItem = m_DefaultMenuItemID;
  562.     bByPos = m_DefaultMenuItemByPos;
  563. }
  564.  
  565. LRESULT CMainFrame::OnTrayNotification(UINT wParam, LONG lParam) 
  566. {
  567.     //Return quickly if its not for this tray icon
  568.     if (wParam != m_tnd.uID)
  569.         return 0L;
  570.  
  571.     CMenu menu, *pSubMenu;
  572.     CWnd* pTarget = AfxGetMainWnd();
  573.  
  574.     // Clicking with right button brings up a context menu
  575.     if (LOWORD(lParam) == WM_RBUTTONUP)
  576.     {    
  577.         if (!menu.LoadMenu(m_tnd.uID)) return 0;
  578.         if (!(pSubMenu = menu.GetSubMenu(0))) return 0;
  579.  
  580.         // Make chosen menu item the default (bold font)
  581.         ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos);
  582.  
  583.         // Display and track the popup menu
  584.         CPoint pos;
  585.         GetCursorPos(&pos);
  586.  
  587.         pTarget->SetForegroundWindow();  
  588.         ::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x, pos.y, 0, 
  589.                          pTarget->GetSafeHwnd(), NULL);
  590.  
  591.         // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly"
  592.         pTarget->PostMessage(WM_NULL, 0, 0);
  593.  
  594.         menu.DestroyMenu();
  595.     } 
  596.     else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) 
  597.     {
  598.         // double click received, the default action is to execute default menu item
  599.         pTarget->SetForegroundWindow();  
  600.  
  601.         UINT uItem;
  602.         if (m_DefaultMenuItemByPos)
  603.         {
  604.             if (!menu.LoadMenu(m_tnd.uID)) return 0;
  605.             if (!(pSubMenu = menu.GetSubMenu(0))) return 0;
  606.             uItem = pSubMenu->GetMenuItemID(m_DefaultMenuItemID);
  607.         }
  608.         else
  609.             uItem = m_DefaultMenuItemID;
  610.         
  611.         pTarget->SendMessage(WM_COMMAND, uItem, 0);
  612.  
  613.         menu.DestroyMenu();
  614.     }
  615.  
  616.     return 1;
  617. }
  618.  
  619. LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  620. {
  621.     if (message == m_tnd.uCallbackMessage)
  622.         return OnTrayNotification(wParam, lParam);
  623.     
  624.     return CWnd::WindowProc(message, wParam, lParam);
  625. }
  626.  
  627.  
  628.  
  629. BOOL CMainFrame::OnNcActivate(BOOL bActive) 
  630. {
  631.     // Add iconize button to caption
  632.     DrawButtons( GetSafeHwnd() );
  633.  
  634.     return CMDIFrameWnd::OnNcActivate(bActive);
  635. }
  636.  
  637.  
  638. void CMainFrame::OnNcLButtonUp(UINT nHitTest, CPoint point) 
  639. {
  640.     HDC        hDc        ;
  641.     RECT    rPos    ;
  642.     RECT    rWin    ;
  643.  
  644.     // Redraw caption buttons
  645.     if ( ( hDc = ::GetWindowDC( GetSafeHwnd() ) ) != NULL )
  646.     {
  647.         // Convert mouse postion relative to caption rectangle
  648.         GetWindowRect(&rWin);
  649.         
  650.         // Calculate rectangle position of iconize button
  651.         CalcCaptionRect( GetSafeHwnd(), rPos );
  652.         rPos.top    += 2;    
  653.         rPos.bottom -= 2;
  654.         rPos.right  -= ( ( GetSystemMetrics( SM_CXSIZE ) * 3 ) );
  655.         rPos.left    = rPos.right - ( GetSystemMetrics( SM_CXSIZE ) - 2 );
  656.  
  657.         point.x = point.x - rWin.left;
  658.         point.y = point.y - rWin.top;
  659.  
  660.         // Check if mouse position is in rectangle
  661.         if ( PtInRect( &rPos, point) )
  662.         {    
  663.             SendMessage( WM_SYSCOMMAND, SC_MINIMIZE, 0 );
  664.             ShowWindow( SW_HIDE );
  665.             ShowIcon();
  666.             ShowTaskBarButton(FALSE);
  667.         }
  668.         else
  669.             CMDIFrameWnd::OnNcLButtonUp(nHitTest, point);
  670.  
  671.         DrawFrameControl( hDc, &rPos, DFC_BUTTON, DFCS_BUTTONPUSH );
  672.         DrawIconize( hDc, rPos.left, rPos.top, 0 );        
  673.         m_LBtnDown = FALSE;
  674.         DeleteObject( hDc );
  675.     }
  676. }
  677.  
  678. void CMainFrame::OnNcLButtonDown(UINT nHitTest, CPoint point) 
  679. {
  680.     HDC        hDc        ;
  681.     RECT    rPos    ;
  682.     RECT    rWin    ;
  683.  
  684.     // Redraw caption buttons
  685.     if ( ( hDc = ::GetWindowDC( GetSafeHwnd()) ) != NULL )
  686.     {
  687.         // Convert mouse postion relative to caption rectangle
  688.         ::GetWindowRect( GetSafeHwnd(), &rWin );
  689.         
  690.         // Calculate rectangle position of iconize button
  691.         CalcCaptionRect( GetSafeHwnd(), rPos );
  692.         rPos.top    += 2;    
  693.         rPos.bottom -= 2;
  694.         rPos.right  -= ( ( GetSystemMetrics( SM_CXSIZE ) * 3 ) );
  695.         rPos.left    = rPos.right - ( GetSystemMetrics( SM_CXSIZE ) - 2 );
  696.  
  697.         point.x = point.x - rWin.left;
  698.         point.y = point.y - rWin.top;
  699.  
  700.         // Check if mouse position is in rectangle
  701.         if ( PtInRect( &rPos, point) )
  702.         {
  703.             m_LBtnDown = TRUE;
  704.             DrawFrameControl( hDc, &rPos, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED );
  705.             DrawIconize( hDc, rPos.left, rPos.top, 1 );            
  706.         }
  707.         else
  708.             CMDIFrameWnd::OnNcLButtonDown(nHitTest, point) ;
  709.         
  710.         DeleteObject( hDc );
  711.     }
  712. }
  713.  
  714. void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point) 
  715. {
  716.     HDC        hDc        ;
  717.     RECT    rPos    ;
  718.     RECT    rWin    ;
  719.  
  720.     // Redraw caption buttons
  721.     if ( ( hDc = ::GetWindowDC( GetSafeHwnd() ) ) != NULL )
  722.     {
  723.         // Convert mouse postion relative to caption rectangle
  724.         ::GetWindowRect( GetSafeHwnd(), &rWin );
  725.         
  726.         // Calculate rectangle position of iconize button
  727.         CalcCaptionRect( GetSafeHwnd(), rPos );
  728.         rPos.top    += 2;    
  729.         rPos.bottom -= 2;
  730.         rPos.right  -= ( ( GetSystemMetrics( SM_CXSIZE ) * 3 ) );
  731.         rPos.left    = rPos.right - ( GetSystemMetrics( SM_CXSIZE ) - 2 );
  732.  
  733.         point.x = point.x - rWin.left;
  734.         point.y = point.y - rWin.top;
  735.  
  736.         // Check if mouse position is in rectangle
  737.         if ( PtInRect( &rPos, point) )
  738.         {
  739.             DrawFrameControl( hDc, &rPos, DFC_BUTTON, ( m_LBtnDown ) ? DFCS_BUTTONPUSH | DFCS_PUSHED : DFCS_BUTTONPUSH );
  740.             DrawIconize( hDc, rPos.left, rPos.top, ( m_LBtnDown ) ? 1 : 0 );
  741.         }
  742.         else
  743.         {
  744.             m_LBtnDown = FALSE;
  745.             DrawFrameControl( hDc, &rPos, DFC_BUTTON, DFCS_BUTTONPUSH );
  746.             DrawIconize( hDc, rPos.left, rPos.top, 0 );
  747.             CMDIFrameWnd::OnNcMouseMove(nHitTest, point) ;
  748.         }
  749.     
  750.         DeleteObject( hDc );
  751.     }
  752. }
  753.  
  754. void CMainFrame::OnNcPaint() 
  755. {
  756.     CMDIFrameWnd::OnNcPaint();
  757.  
  758.     // Add iconize button to caption
  759.     DrawButtons( GetSafeHwnd() );
  760. }
  761.  
  762.  
  763. void CMainFrame::CalcCaptionRect( HWND hWnd, RECT& Rect )
  764. {    
  765.     DWORD dStyle        ;
  766.     SIZE  sFrame        ;
  767.     int      Icon            ;    
  768.  
  769.     // Get frame size of window
  770.     dStyle    = GetWindowLong( hWnd, GWL_STYLE );
  771.     sFrame.cx = GetSystemMetrics( ( dStyle & WS_THICKFRAME ) ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME );
  772.     sFrame.cy = GetSystemMetrics( ( dStyle & WS_THICKFRAME ) ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME );
  773.  
  774.     // Get width of icon/button in caption
  775.     Icon = GetSystemMetrics( SM_CXSIZE );
  776.  
  777.     // Calculate rectangle dimensions
  778.     ::GetWindowRect( hWnd, &Rect );
  779.     Rect.bottom -= Rect.top;
  780.     Rect.right  -= Rect.left;
  781.     Rect.top     = 0;
  782.     Rect.left    = 0;
  783.  
  784.     Rect.left   += sFrame.cx;
  785.     Rect.right  -= sFrame.cx;
  786.     Rect.top    += sFrame.cy;
  787.     Rect.bottom  = Rect.top + GetSystemMetrics( SM_CYCAPTION )
  788.                             - GetSystemMetrics( SM_CYBORDER );
  789. }
  790.  
  791.  
  792.  
  793. void CMainFrame::DrawIconize( HDC hDc, int x, int y, int off )
  794. {
  795.     //
  796.     // TODO:
  797.     // This should be done flikker free by means
  798.     // of a memory DC
  799.     //
  800.  
  801.     HPEN Pen, oldPen;
  802.     HBRUSH Brush, oldBrush;
  803.  
  804.     int     cxBtn = GetSystemMetrics( SM_CXSIZE ) - 5;
  805.     int  cyBtn = GetSystemMetrics( SM_CYSIZE ) - 5;
  806.     
  807.     Pen = CreatePen( PS_SOLID, 1, RGB( 0, 0, 0 ) );
  808.     oldPen = (HPEN)   SelectObject( hDc, Pen );
  809.  
  810.     Brush = CreateSolidBrush( RGB(0,0,0) );
  811.     oldBrush = (HBRUSH) SelectObject(hDc, Brush);
  812.  
  813.     // Use a filled circle in the bottom right corner to signify minimize to icon.
  814.     Ellipse(hDc, x + 1 + cxBtn*1/2 + off, y + 1 + cyBtn*1/2,
  815.         x + 1 + cxBtn*5/6, y + 1 + cyBtn*3/4);
  816.  
  817.     SelectObject( hDc, oldPen );
  818.     DeleteObject( Pen );
  819.  
  820.     SelectObject( hDc, oldBrush );
  821.     DeleteObject( Brush );
  822. }
  823.  
  824. void CMainFrame::DrawButtons( HWND hWnd )
  825. {
  826.     HDC      hDc        ;
  827.     RECT  rCap        ;
  828.     DWORD dStyle    ;
  829.     DWORD dExStyle    ;
  830.     int      cxBtn        ;
  831.     int   cyBtn        ;
  832.     RECT  rPos        ;
  833.  
  834.     // Get window device context        
  835.     if ( ( hDc = ::GetWindowDC( hWnd ) ) != NULL )
  836.     {
  837.         // Get caption coordinates
  838.         CalcCaptionRect( hWnd, rCap );
  839.  
  840.         // Get window style
  841.         dStyle   = GetWindowLong( hWnd, GWL_STYLE );
  842.         dExStyle = GetWindowLong( hWnd, GWL_EXSTYLE );
  843.     
  844.         // Check if we have a caption
  845.         if ( ( dStyle & WS_CAPTION ) == WS_CAPTION )
  846.         {
  847.             // Get button dimensions
  848.             cxBtn = GetSystemMetrics( SM_CXSIZE );
  849.             cyBtn = GetSystemMetrics( SM_CYSIZE );
  850.  
  851.             // Calc position and draw close button
  852.             rPos.top    = rCap.top + 2;
  853.             rPos.bottom = rCap.bottom - 2;
  854.             rPos.right  = rCap.right - 2;
  855.             rPos.left   = rCap.right - 2 - ( cxBtn - 2);
  856.             DrawFrameControl( hDc, &rPos, DFC_CAPTION, DFCS_CAPTIONCLOSE );
  857.  
  858.             // Calc position and draw maximize<->restore/help button
  859.             if ( ( dStyle & WS_MAXIMIZEBOX ) == WS_MAXIMIZEBOX )
  860.             {
  861.                 rPos.right -= cxBtn;
  862.                 rPos.left  -= cxBtn;
  863.                 DrawFrameControl( hDc, &rPos, DFC_CAPTION, ::IsZoomed( hWnd ) ? DFCS_CAPTIONRESTORE 
  864.                                                                             : DFCS_CAPTIONMAX );
  865.             }
  866.             else if ( ( dExStyle & WS_EX_CONTEXTHELP ) == WS_EX_CONTEXTHELP )
  867.             {
  868.                 rPos.right -= cxBtn;
  869.                 rPos.left  -= cxBtn;
  870.                 DrawFrameControl( hDc, &rPos, DFC_CAPTION, DFCS_CAPTIONHELP );
  871.             }
  872.  
  873.             // Calc position and draw minimize and iconize button
  874.             if ( ( dStyle & WS_MINIMIZEBOX ) == WS_MINIMIZEBOX )
  875.             {
  876.                 // Minimize button
  877.                 rPos.right -= ( cxBtn - 2 );
  878.                 rPos.left  -= ( cxBtn - 2 );
  879.                 DrawFrameControl( hDc, &rPos, DFC_CAPTION, DFCS_CAPTIONMIN );
  880.  
  881.                 // Iconize button
  882.                 rPos.right -= ( cxBtn - 2 ) + 2;
  883.                 rPos.left  -= ( cxBtn - 2 ) + 2;
  884.                 DrawFrameControl( hDc, &rPos, DFC_BUTTON, DFCS_BUTTONPUSH );
  885.  
  886.                 // Draw a btnface
  887.                 DrawIconize( hDc, rPos.left, rPos.top, 0 );
  888.             }
  889.         }
  890.  
  891.         // Release device context
  892.         ::ReleaseDC( hWnd, hDc );
  893.     }
  894. }
  895.  
  896. void CMainFrame::OnPaint() 
  897. {
  898.     CPaintDC dc(this); // device context for painting
  899.     
  900.     // Add iconize button to caption
  901.     DrawButtons( GetSafeHwnd() );
  902. }
  903.